<?php
class system_session_namespace extends system_session_abstract implements IteratorAggregate {
	
	const SINGLE_INSTANCE = true;
	protected $_namespace = "default";
	protected static $_namespaceLocks = array();
	protected static $_singleInstances = array();
	
	public static function resetSingleInstance($namespaceName = null) {
		if($namespaceName!=null) {
			if(array_key_exists($namespaceName, self::$_singleInstances)) {
				unset(self::$_singleInstances[$namespaceName]);
			}
			return;
		}		
		self::$_singleInstances = array();
		return;
	}
	
	public function __construct($namespace = 'Default', $singleInstance = false) {
		if($namespace==='') {
			throw new system_session_exception('Session namespace must be a non-empty string.');
		}		
		if($namespace[0]=="_") {
			throw new system_session_exception('Session namespace must not start with an underscore.');
		}		
		if(preg_match('#(^[0-9])#i', $namespace[0])) {
			throw new system_session_exception('Session namespace must not start with a number.');
		}		
		if(isset(self::$_singleInstances[$namespace])) {
			throw new system_session_exception("A session namespace object already exists for this namespace ('$namespace'), and no additional accessors (session namespace objects) for this namespace are permitted.");
		}		
		if($singleInstance===true) {
			self::$_singleInstances[$namespace] = true;
		}		
		$this->_namespace = $namespace;		
		system_session::start(array());
		if(self::$_readable===false) {
			throw new system_session_exception(self::_THROW_NOT_READABLE_MSG);
		}
	}
	
	public function getIterator() {
		return new ArrayObject(parent::_namespaceGetAll($this->_namespace));
	}
	
	public function lock() {
		self::$_namespaceLocks[$this->_namespace] = true;
	}
	
	public function unlock() {
		unset(self::$_namespaceLocks[$this->_namespace]);
	}
	
	public static function unlockAll() {
		self::$_namespaceLocks = array();
	}
	
	public function isLocked() {
		return isset(self::$_namespaceLocks[$this->_namespace]);
	}
	
	public function unsetAll() {
		return parent::_namespaceUnset($this->_namespace);
	}
	
	public function &__get($name) {
		if($name==='') {
			throw new system_session_exception("The '$name' key must be a non-empty string");
		}		
		return parent::_namespaceGet($this->_namespace, $name);
	}
	
	public function __set($name, $value) {
		if(isset(self::$_namespaceLocks[$this->_namespace])) {
			throw new system_session_exception('This session/namespace has been marked as read-only.');
		}		
		if($name==='') {
			throw new system_session_exception("The '$name' key must be a non-empty string");
		}		
		if(parent::$_writable===false) {
			throw new system_session_exception(parent::_THROW_NOT_WRITABLE_MSG);
		}		
		$name = (string) $name;		
		$_SESSION[$this->_namespace][$name] = $value;
	}
	
	public function __isset($name) {
		if($name==='') {
			throw new system_session_exception("The '$name' key must be a non-empty string");
		}		
		return parent::_namespaceIsset($this->_namespace, $name);
	}
	
	public function __unset($name) {
		if($name==='') {
			throw new system_session_exception("The '$name' key must be a non-empty string");
		}
		
		return parent::_namespaceUnset($this->_namespace, $name);
	}
	
	public function getNamespace() {
		return $this->_namespace;
	}
}